import select
import socket
import queue
from core.server import EOM

class Server():
    def __init__(self):
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.socket.setblocking(0)
        self.socket.bind(("0.0.0.0",8888))
        self.socket.listen(20)
        self.e = select.epoll()
        self.e.register(self.socket.fileno(),select.EPOLLIN)
        self.messageQ = {}
        self.sockets: dict(int, socket.socket)= {}

    def start(self):
        while True:
            events = self.e.poll(20)
            if events is None:
                print("timeout. retry poll")
                continue
            for fd,event in events:
                if fd == self.socket.fileno():
                    s, addr = self.socket.accept()
                    self.sockets[s.fileno()] = s
                    self.messageQ[s.fileno()] = queue.Queue()
                    s.setblocking(0)
                    self.e.register(s.fileno(),select.EPOLLIN)
                elif event & select.EPOLLHUP:
                    self.end(fd, event)
                elif event & select.EPOLLIN:
                    content = ""
                    while True:
                        try:
                            content += self.sockets[fd].recv(1024).decode("utf-8")
                            if content == "" or content.endswith(EOM):
                                break
                        except Exception as e:
                            print(e)
                            break
                    if content == "":
                        self.end(fd,event)
                        continue
                    print(content)
                    for cfd,csocket in self.sockets.items():
                        self.messageQ[cfd].put(content)
                        self.e.modify(cfd,select.EPOLLOUT | select.EPOLLIN)
                elif event & select.EPOLLOUT:
                    try:
                        content = self.messageQ[fd].get_nowait()
                    except queue.Empty:
                        print("error")
                        self.end(fd, event)
                    else:
                        self.sockets[fd].send(content.encode("utf-8"))
                        self.e.modify(fd, select.EPOLLIN)
    def end(self,fd: int, event: int):
        self.sockets[fd].close()
        del self.messageQ[fd]
        del self.sockets[fd]
        self.e.unregister(fd)

if __name__ == "__main__":
    Server().start()